package handle

import (
	"server/game/cache"
	"server/game/model"
	"server/share/config"

	"github.com/hwcer/cosgo/random"
	"github.com/hwcer/cosgo/registry"
	"github.com/hwcer/cosgo/times"
	"github.com/hwcer/cosgo/values"
	"github.com/hwcer/cosmo"
	"github.com/hwcer/updater"
	"github.com/hwcer/updater/dataset"
	"github.com/hwcer/yyds"
	"github.com/hwcer/yyds/context"
	"github.com/hwcer/yyds/errors"
)

func init() {
	Register(&Gacha{})
}

/*
Gacha 抽卡扭蛋机
*/

type Gacha struct {
}

func (this *Gacha) Caller(node *registry.Node, handle *context.Context) interface{} {
	f := node.Method().(func(*Gacha, *context.Context) interface{})
	return f(this, handle)
}

// Logs 抽卡记录
func (this *Gacha) Logs(c *context.Context) interface{} {
	paging := &cosmo.Paging{}
	if err := c.Bind(paging); err != nil {
		return err
	}
	paging.Init(100)

	t := times.Daily(-90)
	tx := db.Model(&model.Gacha{}).Where("uid = ?", c.Uid())
	tx = tx.Where("update >= ?", t.Now().Unix())
	//tx = tx.Order("update", -1)
	tx = tx.Omit("_id", "uid")
	if err := tx.Page(paging).Error; err != nil {
		return err
	}
	return paging
}

// Wish 许愿
// id int32 卡池ID
// tar int32  目标,希望得到卡池组的哪一行,为空时取消许愿
func (this *Gacha) Wish(c *context.Context) any {
	id := c.GetInt32("id")
	tar := c.GetInt32("tar")
	cfg := config.Data.Gacha[id]
	if cfg == nil {
		return errors.ErrConfigEmpty
	}
	if cfg.Wish == 0 {
		return c.Error("wish disabled")
	}
	if cfg.Wish != tar {
		return c.Errorf(0, "wish target error")
	}

	gachaGroup := config.Data.GachaGroup[tar]
	if gachaGroup == nil {
		return errors.ErrConfigEmpty
	}
	if gachaGroup.Group != tar {
		return c.Errorf(0, "wish tar error")
	}

	ttl, err := c.Player.Times.Verify(cfg.Times)
	if err != nil {
		return err
	}
	doc := cache.GetItems(c.Player.Updater)
	item, _ := doc.GetOrCreate(id, ttl[1], true)
	doc.SetAttach(item.OID, model.AttachGachaWish, tar)
	return true
}

// Submit 抽卡
//
// 参数 id int32 卡池ID
//
// 参数 num int32 抽卡次数
func (this *Gacha) Submit(c *context.Context) interface{} {
	id := c.GetInt32("id")
	num := c.GetInt32("num")
	if id <= 0 || num <= 0 {
		return errors.ErrArgEmpty
	}
	if num > 10 {
		num = 10
	}
	cfg := config.Data.Gacha[id]
	if cfg == nil {
		return errors.ErrConfigEmpty
	}

	if _, err := c.Player.Times.Verify(cfg.Times); err != nil {
		return err
	}

	handle := c.Player.Collection(config.ITypeGacha)
	handle.Select(id)
	if err := c.Player.Data(); err != nil {
		return err
	}
	doc := cache.GetItems(c.Player.Updater)
	expire, err := c.Player.Times.Expire(cfg.Expire[0], cfg.Expire[1])
	if err != nil {
		return err
	}
	item, loader := doc.GetOrCreate(id, expire, true)
	up := dataset.Update{}
	now := c.Unix()
	value := int32(item.Value)
	if loader && item.Expire < now {
		value = 0
		up.Set("ttl", expire)
	}
	if cfg.Limit > 0 {
		if n := cfg.Limit - int32(item.Value); n <= 0 {
			return c.Errorf(0, "limit:%v/%v", item.Value, cfg.Limit)
		} else if num > n {
			num = n
		}
	}
	//扣除道具
	if cfg.Ticket > 0 {
		if val := int32(c.Player.Val(cfg.Ticket)); val < num {
			return updater.ErrItemNotEnough(cfg.Ticket, num, val)
		}
		c.Player.Sub(cfg.Ticket, num)
	}
	//Reward
	c.Player.Add(cfg.Reward, num)
	//随机
	GachaRandom := config.GetGachaRandom()
	var r int32
	var success []int32
	attach := item.Attach.Clone()

	for i := int32(0); i < num; i++ {
		value += 1
		if num == 10 && cfg.Lucky > 0 && i == 0 {
			//10连小保底
			spec := attach.GetInt32(model.AttachGachaSpec) //获取已经记录的次数
			spec += 1
			attach.Set(model.AttachGachaSpec, spec)
			r = GachaRandom.GroupRandom(cfg.Lucky)
		} else if r = GachaRandom.HelpsExist(id, value); r == 0 {
			group := this.getGroup(cfg, GachaRandom, value, attach)
			if group <= 0 {
				return c.Errorf(0, "Gacha rate random:%v", value)
			}
			if wish := attach.GetInt32(model.AttachGachaWish); wish != 0 && r == cfg.Wish {
				r = wish
			} else {
				r = GachaRandom.GroupRandom(group)
			}
			if r <= 0 {
				return c.Errorf(0, "Gacha group random:%v,group:%v", value, group)
			}
		}
		//随机卡池
		g := config.Data.GachaGroup[r]
		c.Player.Add(g.Item, g.Num)
		success = append(success, r)
	}

	up.Set("val", value)
	up.Set("att", attach)
	doc.Set(item.OID, up)
	c.Player.Emit(config.Data.Events.DrawNum, num)
	//崽崽⌛️
	var drawUnit int32
	for _, v := range success {
		gg := config.Data.GachaGroup[v]
		if gg == nil {
			continue
		}
		it := yyds.Config.GetIType(gg.Item)
		if it == config.ITypeUnit || it == config.ITypeUnitBase {
			drawUnit += 1
		}
	}
	if drawUnit > 0 {
		c.Player.Emit(config.Data.Events.DrawUnit, drawUnit)
	}

	c.Player.Updater.On(updater.EventTypeSuccess, func(u *updater.Updater) (next bool) {
		var vlog []*model.Gacha
		for _, i := range success {
			cg := config.Data.GachaGroup[i]
			iid := cg.Item
			it := yyds.Config.GetIType(iid)
			if it == config.ITypeUnit || it == config.ITypeUnitBase {
				vlog = append(vlog, model.NewGacha(u, iid, id))
			}
		}
		if len(vlog) > 0 {
			_ = db.Create(vlog)
		}

		return false
	})
	return success
}

func (this *Gacha) getGroup(c gachaConfig, GachaRandom *config.GachaRandom, val int32, attach values.Values) int32 {
	g := c.GetSpecG()
	x := c.GetSpecX()
	y := c.GetSpecY()
	spec := attach.GetInt32(model.AttachGachaSpec) //获取已经记录的次数
	spec += 1                                      //加上本次次数+1
	n := spec - x + 1
	defer func() {
		attach.Set(model.AttachGachaSpec, spec)
	}()
	if g > 0 && y > 0 && n > 0 && random.Probability(n*y, 10000) {
		spec = 0
		return g
	} else {
		return getGroupBasic(GachaRandom, c.GetRate())
	}

}

func getGroupBasic(GachaRandom *config.GachaRandom, rate int32) int32 {
	if i := GachaRandom.RateRandom(rate); i > 0 {
		if c := config.Data.GachaRate[i]; c != nil {
			return c.GetGroup()
		}
	}
	return 0
}

type gachaConfig interface {
	GetRate() int32
	GetSpecX() int32
	GetSpecY() int32
	GetSpecG() int32
}
